// 验证码管理

use std::{collections::HashMap};
use std::cmp::Eq;
use std::hash::Hash;
use chrono::{Local, DateTime};
use lettre::Address;
use tokio::sync::Mutex;
use std::convert::TryFrom;
use super::AppData;


#[derive(Debug)]
pub struct VerificationCode<K:Eq+Hash> {
	/// <T,(验证码,生成的时间)>  //不用担心验证码重复,因为 id是 T+验证码
	hash:HashMap<K,(String,DateTime<Local>)>,
	/// 当hash表数量达到什么数量时,清理一次验证码
	number:u64,
	/// 验证码过期时间 ,单位(秒)
	expired_time:u64
}

impl<K:Eq+Hash> VerificationCode<K> {

	pub fn new(number:u64,expired_time:u64)->VerificationCode<K>{
		VerificationCode{
			hash:HashMap::new(),
			number,
			expired_time,
		}
	}

	/// -> true:过期 
	fn is_过期(expired_time:u64,time:&DateTime<Local>)->bool{
		let a = Local::now().timestamp() - time.timestamp();//现在 - 过去
		let a = a as u64;//差,它不应该是负数
		a >= expired_time
	}
	
	pub fn clear(&mut self){
		self.hash.retain(|_,(_,time)|{
			! Self::is_过期(self.expired_time,time)
		});
	}
	
	pub fn insert(&mut self,k:K,v:impl Into<String>){
		self.hash.insert(k, (v.into(),Local::now()));		
		if self.hash.len() >= self.number as usize {
			self.clear();
		}
	}

	/// 随机生成6位数字验证码
	/// -> 验证码
	pub fn insert_6(&mut self,k:K)->String{
		let mut r = String::new();
		for v in 0..6 {
			let i = rand::random::<u64>() % 10 ;//并不平均的0..=9随机数,但是谁又能发现呢
			r = r + &i.to_string();
		}
		self.insert(k, r.clone());
		r
	}
	
	pub fn get(&self,k:&K) -> Option<&String>{
		match self.hash.get(k) {
			Some((v,time)) =>{ 
				if Self::is_过期(self.expired_time, time){
					None
				} else {
					Some(v)
				}
			},
			None => None
		}
	}
}


#[derive(Debug,PartialEq,Eq,Hash)]
pub struct EmailCode(pub Address);

impl EmailCode{
	pub fn try_new(address:impl TryInto<Address>)->Result<EmailCode, ()>{
		match address.try_into() {
			Ok(v) => Ok(EmailCode(v)) ,
			Err(e) => Err(())
		}
	}

}
impl From<Address> for EmailCode {
    fn from(a: Address) -> Self {
        EmailCode(a)
    }
}
impl TryFrom<String> for EmailCode {
    type Error=();

    fn try_from(value: String) -> Result<Self, Self::Error> {
        match TryInto::<Address>::try_into(value) {
			Ok(v) => {
				Ok(EmailCode(v))
			},
			Err(e) => Err(())
		}
    }
}


pub type MVerCodeEmail=Mutex<VerificationCode<EmailCode>>;
impl Default for AppData<MVerCodeEmail> {
    fn default() -> Self {
		// 容量达到 50 后清理一次,清理 10分钟 之前的目标,也就是验证码 10分钟 后就会过期
        AppData::new(Mutex::new(VerificationCode::new(50,60*10)))
    }
}



#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use chrono::Local;
    use delay_timer::prelude::DelayTimerBuilder;

	#[test]
	fn f(){
		
	}

}